package cn.liziguo.tank;

import cn.liziguo.tank.config.GameConfig;
import cn.liziguo.tank.constants.GameEnum;
import cn.liziguo.tank.constants.SpawnsConst;
import cn.liziguo.tank.factory.MapFactory;
import cn.liziguo.tank.factory.WordFactory;
import cn.liziguo.tank.util.JsonUtil;
import com.almasb.fxgl.app.CursorInfo;
import com.almasb.fxgl.app.GameApplication;
import com.almasb.fxgl.app.GameSettings;
import com.almasb.fxgl.dsl.FXGL;
import com.almasb.fxgl.entity.Entity;
import com.almasb.fxgl.entity.SpawnData;
import com.almasb.fxgl.entity.component.Component;
import com.almasb.fxgl.entity.components.ViewComponent;
import com.almasb.fxgl.input.*;
import com.almasb.fxgl.texture.AnimatedTexture;
import com.almasb.fxgl.texture.AnimationChannel;
import javafx.geometry.Point2D;
import javafx.scene.paint.Color;
import javafx.stage.FileChooser;
import javafx.util.Duration;
import org.jetbrains.annotations.NotNull;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * @author Liziguo
 * @date 2022/7/19 11:05
 */
public class TankMapEditor extends GameApplication {

    public static final String MAP_NAME = "map_name";

    private double x = -GameConfig.MAP_UNIT;
    private double y = -GameConfig.MAP_UNIT;

    private String spawn = SpawnsConst.BRICK;
    private int count = 1;

    @Override
    protected void initSettings(GameSettings gameSettings) {
        gameSettings.setTitle("坦克大战地图编辑器");
        gameSettings.setVersion("1.0");
        gameSettings.setAppIcon("ui/tankLoading.png");
        gameSettings.setDefaultCursor(new CursorInfo("ui/cursor.png", 0, 0));
        gameSettings.setWidth(GameConfig.WIDTH);
        gameSettings.setHeight(GameConfig.HEIGHT);
    }

    @Override
    protected void initGame() {
        FXGL.getGameScene().setBackgroundColor(Color.BLACK);
        FXGL.getGameWorld().addEntityFactory(new MapFactory());
        WordFactory.createWord();
        MapFactory.createHome();
        MapFactory.createHomeFence();
        FXGL.entityBuilder().with(new Component() {

            private Input input;

            @Override
            public void onAdded() {
                input = FXGL.getInput();
            }

            @Override
            public void onUpdate(double tpf) {
                x = input.getMouseXWorld();
                y = input.getMouseYWorld();
            }
        }).buildAndAttach();

    }

    @Override
    protected void initInput() {
        Input input = FXGL.getInput();
        input.addTriggerListener(new TriggerListener() {
            @Override
            protected void onActionBegin(@NotNull Trigger trigger) {
                if (trigger.isKey()) {
                    // 请不要在此处监听shift和alt
                    var keyTrigger = (KeyTrigger) trigger;
                    // key is being pressed now
                    var key = keyTrigger.getKey();
                    switch (key) {
                        case DIGIT1 -> count = 1;
                        case DIGIT2 -> count = 2;
                        case DIGIT3 -> count = 3;
                        case DIGIT4 -> count = 4;
                        case DIGIT5 -> count = 5;
                        case Q -> spawn = SpawnsConst.BRICK;
                        case W -> spawn = SpawnsConst.GREENS;
                        case E -> spawn = SpawnsConst.SEA;
                        case R -> spawn = SpawnsConst.SNOW;
                        case T -> spawn = SpawnsConst.STONE;
                        case S -> {
                            String userDir = System.getProperty("user.dir");
                            File initialDirectory = new File(userDir + "/src/main/resources/assets/levels");
                            if (!initialDirectory.isDirectory()) {
                                initialDirectory = new File(userDir);
                            }
                            FileChooser fc = new FileChooser();
                            fc.setInitialDirectory(initialDirectory);
                            fc.setInitialFileName("新关卡");
                            fc.setTitle("地图另存为");
                            fc.getExtensionFilters().add(new FileChooser.ExtensionFilter("json文件", "*.json"));
                            File file = fc.showSaveDialog(FXGL.getPrimaryStage());
                            if (file != null) {
                                List<MapFactory.MapEntity> mapEntities = getAllMap().stream().map(e -> new MapFactory.MapEntity(e.getString(MAP_NAME), e.getX(), e.getY())).toList();
                                try (BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(file))) {
                                    out.write(JsonUtil.toBytes(mapEntities));
                                } catch (IOException e) {
                                    e.printStackTrace();
                                    throw new RuntimeException("地图保存出现异常");
                                }
                            }
                        }
                    }
                }
            }

            @Override
            protected void onAction(@NotNull Trigger trigger) {
                if (trigger.isButton()) {
                    var mouseTrigger = (MouseTrigger) trigger;
                    var btn = mouseTrigger.getButton();
                    int x = (int) TankMapEditor.this.x / GameConfig.MAP_UNIT * GameConfig.MAP_UNIT;
                    int y = (int) TankMapEditor.this.y / GameConfig.MAP_UNIT * GameConfig.MAP_UNIT;
                    switch (btn) {
                        case PRIMARY -> {
                            for (int i = 0; i < count; i++) {
                                for (int j = 0; j < count; j++) {
                                    int x1 = x + GameConfig.MAP_UNIT * j;
                                    int y1 = y + GameConfig.MAP_UNIT * i;
                                    clearByPoint(x1, y1);
                                    FXGL.spawn(spawn, new SpawnData(x1, y1).put(MAP_NAME, spawn));
                                }
                            }
                        }
                        case SECONDARY -> {
                            for (int i = 0; i < count; i++) {
                                for (int j = 0; j < count; j++) {
                                    int x1 = x + GameConfig.MAP_UNIT * j;
                                    int y1 = y + GameConfig.MAP_UNIT * i;
                                    clearByPoint(x1, y1);
                                }
                            }
                        }
                    }
                }
            }

            @Override
            protected void onActionEnd(@NotNull Trigger trigger) {
                if (trigger.isButton()) {
                    for (Entity entity : FXGL.getGameWorld().getGroup(GameEnum.SEA).getEntitiesCopy()) {
                        ViewComponent viewComponent = entity.getViewComponent();
                        viewComponent.clearChildren();
                        AnimationChannel ac = new AnimationChannel(FXGL.image("map/sea_anim.png"), Duration.seconds(1), 2);
                        AnimatedTexture at = new AnimatedTexture(ac);
                        viewComponent.addChild(at.loop());
                    }
                    getAllMap().stream().filter(e -> e.getX() < 0 || e.getX() > GameConfig.WIDTH - GameConfig.MAP_UNIT || e.getY() < 0 || e.getY() > GameConfig.HEIGHT - GameConfig.MAP_UNIT).forEach(Entity::removeFromWorld);

                }
            }
        });
    }

    static void clearByPoint(int x, int y) {
        List<Entity> entitiesAt = FXGL.getGameWorld().getEntitiesAt(new Point2D(x, y));
        entitiesAt.stream().filter(entity -> entity.getPropertyOptional(MAP_NAME).isPresent()).forEach(Entity::removeFromWorld);
    }

    static List<Entity> getAllMap() {
        return FXGL.getGameWorld().getEntitiesFiltered(entity -> entity.getPropertyOptional(MAP_NAME).isPresent());
    }

    public static void main(String[] args) {
        launch(args);
    }
}
